12. 内置数据结构

Python给提供了四种内置基本结构,这四种内置基本结构是:

  • list: 列表

  • set: 集合

  • dict: 字典

  • tuple:元祖

我们把这四种基本结构作为Python提供的标准变量类型使用。

12.1. 列表 list

列表内数据是有顺序的,但对数据的类型没有限制,一般类型(包括我们后面学的实例,类等)基本都可以作为列表内数据的类型, 即列表基本不挑食,啥都能装。

列表内数据有顺序就意味着我们可以对列表的数据按它的排列顺序进行访问。

12.1.1. 列表的定义方式

列表的定义相对简单,一般有三种方式,参看下面案例:

# 定义一个空列表
l1 = list()
print("l1=", l1)

# 定义空列表简写形式
l2 = []
print("l2=",l2)

# 定义一个有数据的列表
# 列表内数据用英文逗号隔开
l3 = [1,2,3]
print("l3=", l3)

我们在上面定义了两个空的列表,还有一个列表内有数据,打印出列表来后结果如下:

l1= []
l2= []
l3= [1, 2, 3]

如果变量是一个列表,则可以通过type打印出列表的类型来:

# 1, 创建空列表
l1 = []
# type是内置函数,负责打印出变量的类型
print(type(l1))
print(l1)

# 2. 创建带值的列表
l2 = [100]
print(type(l2))
print(l2)

# 3. 创建列表,带多个值
l3 = [2,3,1,4,6,4,6]
print(type(l3))
print(l3)

# 4. 使用list()
l4 = list()
print(type(l4))
print(l4)

上面案例打印的结果为,我们打印出了列表的类型和内容:

<class 'list'>
[]
<class 'list'>
[100]
<class 'list'>
[2, 3, 1, 4, 6, 4, 6]
<class 'list'>
[]

12.1.2. 列表常用操作

在对列表的操作中,两类操作十分重要,分别是:

  • 下标访问

  • 分片操作

12.1.2.1. 下标访问

我们的对列表内元素的访问一般可以通过下表来近行。

我们在上面提到过,列表内元素是有顺序的,这种顺序就可以让我们对其按顺序访问,比如我们班级成绩有一个成绩排名,我们可以说班里的第一名,第二名和 第三名用来指代班级的前三名的同学名称,此处这个顺序就是我们访问列表用到的下标(index),需要注意的是在计算机的世界里,下标一般是个比较 常见的名词,而一般下标都是从0开始,这个跟我们日常使用有些区别,即你们班第0名同学就是学习最好的那个。

对下标的访问我们使用中括号[]

下面栗子定义了列表,然后访问列表下标为3的元素,按照上面的讲述,下标从0开始,所以所谓的下标3的应该是第四个内容。

# 下标访问列表
l = [3,2,1,4,6,3,2]

print("第四个元素是:", l[3])

答案就是下面:

第四个元素是: 4

12.1.2.2. 切片操作

既然列表内容是排好队的,我们也可以用一个区域来表示一批元素,比如你们班从第四名开始到第十名的同学,都是很有潜力的好苗子,此处第四名到 第十名就表示一个区域,此类操作我们叫做切片,即通过开始和结束下标截取列表的一段内容的操作。

切片操作的符号一般是 [start:end],此处startend 表示开始和结束的下标, 参见下面案例:

l = [3,2,1,4,6,3,2]
# 分片操作
# 注意截取的范围,包含左边的下标值,不包含右边的下标值
print(l[1:4])

# 下标值可以为空,如果不写,左边下标值默认为0, 右边下标值为最大数加一,即表示截取到最后一个数据
print(l[:])
print(l[:4])
print(l[2:])

上面案例需要作出几点说明:

  1. 切片的语法【1:4】表示下标区间是一个左闭区间右开区间的范围[1,4), l[1:4]表示从下标1开始到下标4结束的所有内容, 但不包括下标4的元素。

  2. 开始和结束下标都可以采用默认值,但分割符号:不能省略。

  3. 开始下标省略则从0开始,结束下标省略则到最后一个元素。

  4. 结束下标可以超过列表的下标最大值,此时自动到最后一个元素结束。

根据上面的规则,上面代码运行结果如下:

[2, 1, 4]
[3, 2, 1, 4, 6, 3, 2]
[3, 2, 1, 4]
[1, 4, 6, 3, 2]

切片操作除了常见的开始结束下标,我们还可以控制步长,即每隔几个元素截取一次,我们用第三个参数来表示,例如 l[1:100:5]表示从下标为1的 元素开始,每隔5个元素截取一个。

默认的步长是1, 我们可以省略,看下面案例:

l = [3,2,1,4,6,3,2]
# 分片操作
print(l)
# 分片可以控制增长幅度,默认增长幅度为1
print(l[1:6:1])

# 打印从下标1开始的数字,每次隔一个
print(l[1:6:2])

# 下标可以超出范围,超出后不在考虑多余下标内容
print(l[2:10])

上面代码运行结果如下:

[3, 2, 1, 4, 6, 3, 2]
[2, 1, 4, 6, 3]
[2, 4, 3]
[1, 4, 6, 3, 2]
[3, 2, 1]

对于切片的步长,可以为负值,此时负号表示截取的方向是从后向前截取,值表示的是步长。

列表的下标也可以是负数,表示从最后一个元素开始向前标注,最后一个元素下标是-1, 依次向前则是-2,-3,-4... ...,这个跟从前向后方向的表示 不太一样。

请看下面栗子:

# 分片之负数下标
print(l)
# 下面显示的是为空,因为默认分片总是从左向右截取
# 即正常情况,分片左边的值一定小于右边的值
print(l[-2:-4])
print(l[-4:-2])
# 如果分片一定左边值比右边大,则步长参数需要使用负数
# 此案例为一个list直接正反颠倒提供了一种思路
print(l[-2:-4:-1])

案例运行结果如下:

[3, 2, 1, 4, 6, 3, 2]
[]
[4, 6]
[3, 6]

12.1.2.3. 分片操作是生成一个新的list

现在的问题是, 我们利用切片操作可以得到一个新的列表,Python规定,切片操作得到的列表都是原来列表的 内容的复制,即切片生成了一个新的列表,这个通过id函数可以得到验证。

下面案例验证了列表的切片操作是重新生成列表的判断:

# 通过id可以直接判断出分片是从新生成了一份数据还是使用的同一份数据
l = [3,4,56,76,32,21,43,5]
ll = l[:]
lll = ll
# 如果两个id值一样,则表明分片产生的列表是使用的同一地址同一份数据
# 否则,则表明分片是从新生成了一份数据,即一个新的列表,然后把数值拷贝到新列表中
print(id(l))
print(id(ll))
print(id(lll))

# 通过id知道,ll和lll是同一份数据,验证代码如下
l[1] = 100
print(l)
print(ll)

ll[1] = 100
print(ll)
print(lll)

运行结果如下:

140226763582408
140226318124808
140226318124808
[3, 100, 56, 76, 32, 21, 43, 5]
[3, 4, 56, 76, 32, 21, 43, 5]
[3, 100, 56, 76, 32, 21, 43, 5]
[3, 100, 56, 76, 32, 21, 43, 5]

12.1.3. 列表的遍历

对列表进行遍历一般用 for循环,当然如果需要,也可以用while循环。

因为已经学习过循环结构,我们直接看下案例:

# for in list
a = [1,2,3,4,5]

# 挨个打印a里边的元素
for i in a:
    print(i)

运行结果如下:

1
2
3
4
5

对于列表的访问,Python继承了脚本语言的一些特点,简洁明了,下面是一个幽默故事,说 java程序员如果不仔细看python语法,会这样访问列表:

# java, c++ 程序员写的python代码是这样的
for i in range(0,len(a)):
    print(a[i])
    i += 1

我们还可以用while循环访问列表,案例如下:

# while循环访问list
# 一般不用while遍历list

a = [1,2,3,4,5,6]
length = len(a)
# indx表示的是list的下标
indx = 0
while indx < length:
    print(a[indx])
    indx += 1

for,while循环一般可以互换,但在实际使用中,这俩有比较明显的使用场景,一般也不互换使用,此处 只是作为案例讲解。

12.1.4. 列表的嵌套

列表可以放入的内容类型比较多,包括列表本身,这样就形成了嵌套列表,我们对嵌套列表的访问一般需要 用到嵌套循环,但有些比较特殊的情况需要注意,就是如果列表中内容比较少,我们可以利用一起定义几个变量 的方法,此时被嵌套的列表的内容会按顺序赋值给变量,请看下面案例:

#a 为嵌套列表,或者叫双层列表
a = [["one", 1], ["two", 2], ["three", 3] ]

for k,v in a:
    print(k, "--", v)

上面代码执行过程中,会一次取出每个小列表,然后自动把小列表中的内容赋值给k,v, 代码运行结果如下:

one -- 1
two -- 2
three -- 3

上面这种情况有一个前提就是小列表中内容个数和前面定义的变量个数必须一致,否则报错

当然,这里的数量并没有明确限制,只要变量数量和小列表长度能对应上就可以了。

下面案例是三个变量的案例:

# 双层列表循环变异

#a 为嵌套列表,或者叫双层列表
a = [["one", 1, "eins"], ["two", 2,"zwei"], ["three", 3,"drei"] ]
#这个例子说明,k,v,w的个数应该跟解包出来的变量个数一致
for k,v,w in a:
    print(k, "--", v, "--",w)

运行结果如下:

one -- 1 -- eins
two -- 2 -- zwei
three -- 3 -- drei

12.1.5. 列表生成式

列表生成式就是通过一些简单的方法生成一个列表。

下面案例就是一共列表生成式,我们通过列表的内容遍历生成了一个新的列表,需要注意格式, 这是一种固定写法。

  • 简单列表生成式

      a = ['a', 'b', 'c']
      # 用list a创建一个list b
      # 下面代码的含义是,对于所有a中的元素,逐个放入新列表b中
      b = [i for i in a]
      print(b)
    

    在使用列表生成式的时候,还可以对内容进行简单处理,这种处理一般相对简单,限定在一行内,过于复杂 请使用for循环处理。

  • 列表生成式对内容进行统一操作

    下面案例在生成列表的时候,对源列表内容进行了乘法操作:

      # 对a中所有元素乘以10,生成一个新list
      a = [1,2,3,4,5]
      # 用list a创建一个list b
      # 下面代码的含义是,对于所有a中的元素,逐个放入新列表b中
      b = [i*10 for i in a]
    
  • 加入选择条件的列表生成式

    在使用列表生成式的时候,有时候需要对源列表内元素进行筛选,也就是加上一些条件,此时需要使用 更复杂的列表生成式,即加入限定条件。

    如果需要加入限定条件,直接在后面使用if语句即可。

      # 还可以过滤原来list中的内容病放入新列表
      # 比如原有列表a, 需要把所有a中的偶数生成新的列表b
      a = [x for x in range(1,35)] #生成从1到34的一个列表
      # 把a中所有偶数生成一个新的列表 b
      # if语句放在后面
      b = [m for m in a if m % 2 == 0]
    
  • 嵌套列表生成式

    列表生成式可以嵌套使用,可以把嵌套列表生成式看做是嵌套循环,最后生成一个结果。

    只不过写法是固定格式,写成一列而已。

      # 由两个列表a,b
      a = [i for i in range(1,4)] # 生成list a
      b = [i for i in range(100,400) if i % 100 == 0]
    
      # 列表生成是可以嵌套,此时等于两个for循环嵌套
      c = [  m+n for m in a for n in b]
    

    上面代码执行结果跟嵌套循一致,但写法上简洁好多:

      # 上面代码跟下面代码等价
      for m in a:
          for n in b:
              print(m+n, end="  ")
    
  • 带条件的嵌套列表生成式

    把嵌套列表生成式和判断条件加在一起组合成一个复杂的东东,其实完全可以看做是一个嵌套循环,在最里面执行 了一个判断条件:

      # 嵌套的列表生城市也可以用条件表达式
      c = [  m+n for m in a for n in b if m+n < 250]
    

12.1.6. 列表的常用内容功能

函数内置数据结构不仅仅是一堆数据,还有依赖于这些数据的一系列功能,我们把此类功能叫做函数(见函数章节), 这里先把列表的函数或者功能 给大家做个简单介绍。

  • del: 删除列表内某个元素

    del命令比较特殊,他可以删除机会任何东西,包括列表本身,变量等

      # del 删除
      a = [1,2,3,4,5,6]
      del a[2]
      print(a)
    

    运行结果如下:

      [1, 2, 4, 5, 6]
    

    下面案例证明了,如果列表被删除了某个元素,则生成了一个新的列表,也就是说,python并不是在原地址上对列表 内容进行了更改,而是重新开辟了一个内存,把删除后的列表内容拷贝到了新的内存:

      # del 删除
      # 如果使用del之后,id的值和删除前不一样,则说明删除生成了一个新的list
      a = [1,2,3,4,5,6]
      print(id(a))
      del a[2]
      print(id(a))
      print(a)
    

    运行结果如下:

      140246810905416
      140246810905416
      [1, 2, 4, 5, 6]
    

    同时del还可以删除一个完整的列表,或者任意变量:

      # del一个变量后不能在继续使用此变量
      del  a
      print(a)
    

    运行上面代码后得到下面错误信息,提示变量a未定义,因为已经把这个变量删除了:

          NameError Traceback (most recent call last)
    
          <ipython-input-14-94bf5611738e> in <module>()
                1 del  a
          ----> 2 print(a)
    
          NameError: name 'a' is not defined
    
  • 列表相加操作

    列表可以用数学上的加号(+)操作,结果是两个列表内容组合在了一起,注意这种组合是完全的按先后顺序拼接在了一起:

      # 使用加号链接两个列表
      a = [1,2,3,4,5]
      b = [5,6,7,8,9]
      d = ['a', 'b', 'c']
      c = a + b + d
      print(c)
    

    运行结果如下:

          [1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 'a', 'b', 'c']
    

    通过加号操作会生成新的列表,id的值跟任何一个列表都不同

  • 列表和数字相乘

    乘法是加法的省略,所以,列表也可以跟数字相乘,此时代表多少个列表相加。

      # 使用乘号操作列表
      # 列表直接跟一个整数相乘 
      # 相当于把n个列表接在一起
      a = [1,2,3,4,5]
      b = a *3
      print(b)
    

    运行结果如下:

      [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
    
  • in 操作

    in应该属于操作符的一种,学名成员运算符,用来判断一个变量内容是否在一个列表里,同样也可以在字典等类型上使用。

    in操作的结果是一个布尔值。

      # 成员资格运算
      # 就是判断一个元素是否在爱list里边
      a = [1,2,3,4,5,6]
      b = 8
    
      #c 的值是一个布尔值
      c = b in a
      print(c)
    
      b = 4
      print(b in a)
    

    运行结果如下:

      False
      True
    

    又一个栗子:

      # not in 
      a = [1,2,3,4,5]
      b = 9
    
      print(b not in a)
    

    运算结果如下:

      True
    
  • max/min函数,求最大/最小值

      # max:求列表中的最大值
      # min: 同理
      print(max(a))
    
      b = ['man', 'film', 'python']
      print(max(b))
    
  • list定义函数

    用一个值定义一个列表,这个值可以是别的不是列表的内容,比如后面要讲的元祖。

    需要注意的是,如果尝试把一个字符串放入列表中,默认会把字符串拆成一个由各个字符组成的列表,举个栗子:

      s = "I love wangxiaojing"
      l = list(s)
      print(l)
    

    上面代码运行结果如下:

      ['I', ' ', 'l', 'o', 'v', 'e', ' ', 'w', 'a', 'n', 'g', 'x', 'i', 'a', 'o', 'j', 'i', 'n', 'g']
    
  • append:末尾追加元素

    append是在列表末尾追加一个元素。

      # append 插入一个内容, 在末尾追加
      a = [ i for i in range(1,5)]
      print(a)
      a.append(100)
      print(a)
    

    执行结果如下:

      [1, 2, 3, 4]
      [1, 2, 3, 4, 100]
    
  • insert: 插入元素

    向列表中插入元素不但要知道插入的值,还要知道插入的位置,这里的位置下标指的是在此下标前插入。

      # insert: 制定位置插入
      # insert(index, data), 插入位置是index前面
      print(a)
      a.insert(3, 666)
      print(a)
    

    运行结果如下:

      [1, 2, 3, 4, 100]
      [1, 2, 3, 666, 4, 100]
    
  • pop: 弹出元素

    pop是从列表中弹出某个元素,此操作返回结果是弹出的那个元素值,同时因为元素弹出了就不在列表里面,所以 也当做删除使用。

      # 删除
      # del 删除
      # pop,从对位拿出一个元素,即把最后一个元素取出来
      print(a)
      last_ele = a.pop()
      print(last_ele)
      print(a)
    

    运行结果如下:

      [1, 2, 3, 666, 4, 100]
      100
      [1, 2, 3, 666, 4]
    
  • remove: 删除

    此删除操作要求明确知道删除哪个值,操作的参数是删除元素具体的值。

      remove:在列表中删除指定的值的元素
      如果被删除的值没在list中,则报错
      即,删除list指定值的操作应该使用try。。。excepty语句,或者先行进行判断
      if x in list:
         list.remove(x)
    
  • clear:清空操作

    这个操作把列表内容清空,需要注意的是如果只是需要一个空列表,完全可以在生成一个空列表赋值给变量就可以, clear只在还不想更改原来列表地址的时候使用。

      # clear:清空
      print(a)
      print(id(a))
      a.clear()
      print(a)
      print(id(a))
    
      # 如果不需要列表地址保持不变,则清空列表可以使用以下方式
      # a = list()
      # a = []
    

    运行结果如下:

      [1, 2, 3, 4]
      140249408978184
      []
      140249408978184
    
  • reverse:翻转列表内容,原地翻转

      a = [ 1,2,3,4,5]
      print(a)
      print(id(a))
    
      a.reverse()
    
      print(a)
      print(id(a))
    

    上面案例运行结果如下,可以看出reverse是在原列表翻转内容。

      [1, 2, 3, 4, 5]
      140249409135624
      [5, 4, 3, 2, 1]
      140249409135624
    
  • extend:扩展列表,两个列表,把一个直接拼接到后一个上

     a = [ 1,2,3,4,5]
     b = [6,7,8,9,10]
     print(a)
     print(id(a))
    
     a.extend(b)
    
     print(a)
     print(id(a))
    

    extend是把原列表直接扩充了,列表地址保存不变:

     [1, 2, 3, 4, 5]
     140249408367816
     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
     140249408367816
    
  • count:查找列表中指定值或元素的个数

      print(a)
      a.append(8)
      a.insert(4, 8)
      print(a)
      a_len = a.count(8)
      print(a_len)
    

    运行结果如下:

      [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 8]
      [1, 2, 3, 4, 8, 5, 6, 7, 8, 9, 10, 8, 8]
      4
    
  • copy: 拷贝,此函数是浅拷贝,

    copy函数属于浅拷贝,建议慎用。

    深浅拷贝建议参考相关资料,这里可以粗暴的理解成,浅拷贝如果遇到嵌套列表,则只把列表第一层内容拷贝过去, 但嵌套的列表只是拷贝了一个指向,并没真正生成一份子列表

    下面案例比较啰嗦,但比较好的演示了关于列表变量赋值和拷贝的问题:

      # 列表类型变量赋值示例
      # 此类赋值,只是一个指向原列表的链接,数据并没有真正的拷贝,两个变量共用一份数据
      a = [1,2,3,4,5,666]
      print(a)
      # list类型,简单赋值操作,是传地址
      b = a
      b[3] = 777
      print(a)
      print(id(a))
      print(b)
      print(id(b))
    
      print("*" * 20)
    
      # 为了解决以上问题,list赋值需要采用copy函数
      b = a.copy()
      print(a)
      print(id(a))
      print(b)
      print(id(b))
    
      print("*" * 30)
    
      b[3] = 888
      print(a)
      print(b)
    

    运行结果如下:

      [1, 2, 3, 4, 5, 666]
      [1, 2, 3, 777, 5, 666]
      140249408975432
      [1, 2, 3, 777, 5, 666]
      140249408975432
      ********************
      [1, 2, 3, 777, 5, 666]
      140249408975432
      [1, 2, 3, 777, 5, 666]
      140249408976776
      ******************************
      [1, 2, 3, 777, 5, 666]
      [1, 2, 3, 888, 5, 666]
    

    下面案例压实了深浅拷贝的问题,在嵌套列表拷贝的时候,浅拷贝会带来潜在问题:

    解决方式: python模块copy中有deepcopy函数,可以进行深拷贝

      # 深拷贝跟浅拷贝的区别
      # 出现下列问题的原因是,copy‘函数是个浅拷贝函数,即只拷贝一层内容
      # 深拷贝需要使用特定工具
      a = [1,2,3, [10, 20, 30]]
      b = a.copy()
      print(id(a))
      print(id(b))
      print(id(a[3]))
      print(id(b[3]))
      a[3][2] = 666
      print(a)
      print(b)
    

    上面案例运行结果如下:

      140249408365768
      140249409236040
      140249409236232
      140249409236232
      [1, 2, 3, [10, 20, 666]]
      [1, 2, 3, [10, 20, 666]]
    

12.2. 元组:tuple

元组就是一个不可更改的list,把列表中跟更改相关的操作删掉基本就是一个元祖。

元祖存在的意义就是当一个列表不需要进行更改,或者为了防止列表被中途更改,则直接定义成元祖。

12.2.1. 元组创建

元祖创建只能在定义的时候创建,然后就只能进行读操作。

  • 创建一个空元组

      t = ()
      print(type(t))
    
      t = tuple()
      print(type(t))
    
  • 创建一个只有一个值的元组

    此时在括号内需要使用逗号,因为如果没有逗号,则应该被理解成括号内有一个数字,此时括号不起作用,最终得到的是一个数字。

      t = (1,)
      print(type(t))
      print(t)
    
      # 省略掉小括号也可以
      t = 1,
      print(type(t))
      print(t)
    
  • 创建多个值的元组

     t = (1,2,3,4,5)
     print(type(t))
     print(t)
    
     t =  1,2,3,4,5
     print(type(t))
     print(t)
    
  • 使用其他结构创建

      l = [1,2,3,4,5]
      t = tuple(l)
      print(type(t))
      print(t)
    

12.2.2. 元组的特性

  • 是序列表,有序

  • 元组数据值可以访问,不能修改,不能修改,不能修改

  • 元组数据可以是任意类型

  • 总之,list所有特性,除了可修改外,元组都具有

  • 也就意味着,list具有的一些操作,比如索引,分片,序列相加,相乘,成员资格操作等,一模一样

上面千言万语就一句话:元祖就是不可以更改的列表

# 索引操作
t = (1,2,3,4,5)
print(t[4])


# 切片, 切片生成新的元祖,所以是可以的,不算写操作
t = (1,2,3,4,5,6)
t1 = t[1::2]
print(id(t))
print(id(t1))
print(t1)

# 切片可以超标
t2 = t[2:100]
print(t2)

# 序列相加
# 元祖相加生成新的元组,不算写操作
t1 = (1,2,3)
t2 = (5,6,7)


# 元组相乘
t = (1,2,3)
t = t * 3
print(t)

# 成员检测
t = (1,2,3)
if 2 in t:
    print("YES")
else:
    print("NO")

12.3. 集合: set

此处集合和高中数学中的集合概念一致。

用来表示一堆确定的无序的无重复的数据集。

12.3.1. 集合的定义

集合的定义比较简单,分为定义空集合和有内容的集合两种:

  • 定义空集合

      s = set()
    
  • 定义有内容的集合

    用大括号来定义有内容的集合,此时,大括号内一定要有值,否则定义出的是一个字典,不是集合类型。

      s = {1,2,3,4,5,6,7}
    

12.3.2. 集合的特征

  • 集合内数据无序,即无法使用索引和分片

  • 集合内部数据元素具有唯一性,可以用来排除重复数据

  • 集合内的数据,可以是str, int, float, tuple,冰冻集合等,但必须是可哈希数据

12.3.3. 集合操作

  • 成员检测: in, not in

    此类操作返回结果是布尔值,一般常用来做分支语句的条件:

          s = {4,5,"i", "love", "wangxiaojing"}
    
          if "love" in s:
              print("爱呀")
          if  "haha" not in s:
              print("挨个锤子")
    
  • 集合遍历操作

    遍历集合一般用循环来完成:

          # for 循环
          s = {4,5,"i", "love", "wangxiaojing"}
    
          for i in s:
              print(i, end=" ")
    

    如果集合里面元素是元祖类型,我们可以使用一个简写:

      # 带有元组的集合遍历
      s = {(1,2,3), ("i", "love", "wangxiaojing"), (4,5,6)}
    
      for k,m,n in s:
          print(k, "--", m, "--", n)
    
  • 集合的生成式

    跟列表类似,集合也可以用生成式来自动生成。

      # 普通集合内涵
      # 以下集合在初始化后自动过滤掉重复元素
      s = {23,223,545,3,1,2,3,4,3,2,3,1,2,4,3}
    
      # 普通集合内涵
      ss = {i for i in s}
    

    生成式还可以加上一些条件:

          # 带条件的集合内涵
          sss = {i for i in s if i % 2 == 0}
    

    嵌套类型的也可以有:

          # 多循环的集合内涵
          s1 = {1,2,3,4}
          s2 = {"i", "love", "wangxiaojing"}
    
          s = {m*n for m in s2 for n in s1}
          print(s)
    
          s = {m*n for m in s2 for n in s1 if n ==2}
          print(s)
    

    上面运行的结果如下,需要注意的是集合打印的时候,因为集合没有顺序,所以打印结果不是我们想的排好顺序的:

      {'iii', 'i', 'lovelovelove', 'ii', 'lovelovelovelove', 'wangxiaojingwangxiaojingwangxiaojingwangxiaojing', 'wangxiaojing', 'lovelove', 'wangxiaojingwangxiaojing', 'love', 'wangxiaojingwangxiaojingwangxiaojing', 'iiii'}
      {'lovelove', 'wangxiaojingwangxiaojing', 'ii'}
    
  • len, max, min:跟其他基本函数一致

    分别返回集合的长度,最大值,最小值,这个跟列表操作基本一致。

      s = {43,23,56,223,4,2,1222,4,323,1}
      print(len(s))
      print( max(s))
      print(min(s))
    
  • add:向集合内添加元素

      s = {1}
      s.add(334)
    
  • clear: 清空集合

      s = {1,2,3,4,5}
      print(id(s))
      s.clear()
      print(id(s))
      # 结果表明clear函数是原地清空数据
    

    运行结果如下:

      140040159572936
      140040159572936
    
  • copy:拷贝

  • remove:移除制定的值,直接改变原有值,如果要删除的值不存在,报错

  • discard:移除集合中指定的值,跟remove一样,但是要删除的值不在也不报错

      s = {23,3,4,5,1,2,3}
      s.remove(4)
      s.discard(1)
      s.discard(1100)
      s.remove(1100)
    
  • pop: 随机移除一个元素

    列表中的pop默认是把最后一个取出来,但集合没有顺序概念,所以,这个函数最后取出哪个值,完全 不是我们想象的,等同于随机删除。

  • 集合特有的操作

    集合因为他的概念,有一些特有的操作,比如交差并补,是否是子集等,每个都对应相应的操作函数

  • intersection: 交集

  • difference:差集

  • union: 并集

  • 判断类操作

    • issubset: 检查一个集合是否为另一个子集

    • issuperset: 检查一个集合是否为另一个超集

      s1 = {1,2,3,4,5,6} s2 = {5,6,7,8,9}

      s_1 = s1.intersection(s2) print(s_1)

      s_2 = s1.difference(s2) print(s_2)

      s_3 = s1.issubset(s2) print(s_3)

    代码运行结果:

      {5, 6}
      {1, 2, 3, 4}
      False
    

    集合的交差并补每个还有一个操作符号:

      s1 = set([1,2,3,4,5])
      s2 = set([3,4,5,6,7,8])
    
    
      print(s1-s2) #差集
      print(s1 & s2)#交
      print(s1 | s2)#并
      print(s1 ^ s2)#补
    

    运行结果如下:

      {1, 2}
      {3, 4, 5}
      {1, 2, 3, 4, 5, 6, 7, 8}
      {1, 2, 6, 7, 8}
    

12.4. 冰冻集合: frozen set

冰冻集合就是不能进行写操作的集合,除了定义和不能进行修改,其余的跟集合一致。

  • 创建

      s = frozenset()
      print(type(s))
      print(s)
    

    结果显示如下:

      <class 'frozenset'>
      frozenset()
    

12.5. 字典: dict

字典是一种组合数据,是一种没有顺序的组合数据,数据以键值对形式出现。

12.5.1. 字典的定义

  • 空字典定义

    可以使用大括号直接定义一个空的字典, 也可以使用字典类直接定义。

          # 字典的创建
          # 创建空字典1
          d = {}
    
          # 创建空字典2
          d = dict()
    
  • 有数据的字典

    因为字典内数据为键值对,可以直接使用键值对来定义有数据的字典。

          # 创建有值的字典, 每一组数据用冒号隔开, 每一对键值对用逗号隔开
          d = {"one":1, "two":2, "three":3}
    
          # 用dict创建有内容字典1
          d = dict({"one":1, "two":2, "three":3})
    

    在用字典类创建字典的时候,可以使用关键字参数来完成(函数中会讲),参加下面案例:

          # 用dict创建有内容字典2
          # 利用关键字参数
          d = dict(one=1, two=2, three=3)
    

    字典创建字典的时候,还可以使用列表或者元祖作为参数,此时要求创建字典的括号内是一个形如列表,列表内是键值 对的格式的内容,下面几种都是可以的:

      # 列表内嵌套元祖
      d = dict( [("one",1), ("two",2), ("three",3)])
      # 元组内嵌套元组
      d = dict( (("one",1), ("two",2), ("three",3)) )
      # 列表内嵌套列表,最内的列表是两个元素构成的,分别代表键值
      d = dict( [["one",1], ["two",2], ["three",3]] )
    

12.5.2. 字典的特征

  • 字典是序列类型,但是是无序序列,所以没有分片和索引

  • 字典中的数据每个都由键值对组成,即kv对(key:value)

    • key: 必须是可哈希的值,比如int,string,float,tuple, 但是,list,set,dict 不行

    • value: 基本是任何值

  • 为了方便循环操作,可以利用字典内置的功能分别把键,值作或键值对作为可迭代的内容返回

12.5.3. 字典常见操作

  • 访问字典数据

    通常来讲访问字典内数据采用键来访问,参见下面代码:

          # 访问数据
          d = {"one":1, "two":2, "three":3}
          # 注意访问格式
          # 中括号内是键值
          print( d["one"] )
    
          # 对字典内容赋值
          d["one"] = "eins"
          print(d)
    
          # 删除某个操作
          # 使用del操作
          del d["one"]
          print(d)
    

    上述代码运行结果如下:

          1
          {'one': 'eins', 'two': 2, 'three': 3}
          {'two': 2, 'three': 3}
    
  • 成员操作:in,not in

    成员检测符innot in

    字典也可以有成员操作,如果用单个值直接对字典使用成员操作,则默认是检测这个值是否在字典的key中:

          # 成员检测检测的是key内容
          d = {"one":1, "two":2, "three":3}
    
          if 2 in d:
              print("value")
    
          if "two" in d:
              print("key")
    
          if ("two",2) in d:
              print("kv")
    

    最终运行结果只有一个key

          key
    
  • 遍历操作

    字典的遍历操作在Python2.xPython3.x中差别比较大,完全不通用。

    以下遍历分别对键,值,键值对进行遍历,写法相对固定。

    下面代码是Python2.x代码的一个示例:

          # 便利在python2 和 3 中区别比较大,代码不通用
          # 按key来使用for循环
          d = {"one":1, "two":2, "three":3}
          # 使用for循环,直接按key值访问
          for k in d:
              print(k,  d[k])
    

    Python3.x中,我们需要使用keys函数来生成可迭代对象后再遍历,以下遍历为固定写法:

      # 上述代码可以改写成如下
      for k in d.keys():
          print(k,  d[k])
    

    如果需要遍历字典的值的部分,则需要借助values来进行遍历:

      # 只访问字典的值
      for v in d.values():
          print(v)
    

    如果想同时访问字典内元素的键值,则可以借助于items来完成:

      # 注意以下特殊用法
      for k,v in d.items():
          print(k,'--',v)
    

12.5.4. 字典生成式

字典也可以时候用生成式来完成新字典的创建。使用方式跟列表类似。

  • 普通青年的字典生成式

    以下代码使用字典生成式创建新的字典:

          d = {"one":1, "two":2, "three":3}
    
          # 常规字典生成式
          dd = {k:v for k,v in d.items()}
    
  • 加限制条件的字典生成式

      # 只有值为偶数的才会生成新的字典
      dd = {k:v for k,v in d.items() if v % 2 == 0}
    

12.5.5. 字典相关函数

字典相关函数操作比较多,这里我就介绍几个比较重要的。

  • clear: 清空字典

  • items/keys/values: 返回字典的键值对/键/值组成的元组格式

    这三个函数比较常用,我们在上面案例中已经有了展示, 这里需要注意的是它们返回的格式,分别是 dict_items/dict_keys/dict_values格式,不用过多关注这三个格式的具体形式,只需要记住这三个 格式是可迭代的就好,可迭代概念我们在语法高级部分讲述。

  • get: 根据制定键返回相应的值

    对字典的值的访问,我们可以通过形如dict_var['key']来使用,但这个有个问题是如果访问的键并不在 字典里面,会直接引发错误,而使用get函数相对温和一些,可以指定当键不存在的时候我们返回什么。

      d = {"one":1, "two":2, "three":3}
      # 如果 on333 并不在键里面,则默认返回None
      print(d.get("on333"))
    
      # get可以设置键不存在时返回的值
      print(d.get("one", 100))
      print(d.get("one333", 100))
    

    上面代码运行的结果分别是:

      None
      1
      100
    
  • fromkeys: 快速生成字典

    字典可以快速生成,比如我们有一个列表保存的是字典的键,则可以使用fromkeys把列表内的值作为键,此时 可以指定一个值作为这些键的值。

          # fromkeys: 使用指定的序列作为键,使用一个值作为字典的所有的键的值
          l = ["eins", "zwei", "drei"]
          # 注意fromkeys两个参数的类型
          # 注意fromkeys的调用主体
          d = dict.fromkeys(l, "hahahahahah")
          print(d)
    

    上面代码执行结果如下:

      {'eins': 'hahahahahah', 'zwei': 'hahahahahah', 'drei': 'hahahahahah'}
    

12.6. str相关操作

官方文档:内置类型:字符串

https://docs.python.org/3.7/library/stdtypes.html#text-sequence-type-str

12.6.1. (一) 英文字符与字符检测相关函数

# 字符串相关函数 (一) 英文字符与字符检测相关函数
vars = 'iloveyou'
# 返回字符串的副本,该字符串的首个字符大写,其余小写。
# str.capitalize()
res = vars.capitalize()
# 把字符串中的一个单词的首字母大写
res = vars.title()
# 把字符串全部改为 大写
res = vars.upper()
# 把字符串全部改为 小写
res = vars.lower()
# 字符串中的大小写字符转换,大写转小写,小写转大写
res = vars.swapcase()

# 检测字符串是否为全部大写字母组成
res = vars.isupper()
# 检测字符串是否为全部小写字母组成
res = vars.islower()
# 检测字符串是否符合标题title的要求
res = vars.istitle()
# 检测字符串是否由数字和字母组成,如果字符串中包含来非数字字母的其它字符,则返回False
res = vars.isalnum()
# 检测字符串是否全部由字符(包含英文字符和中文)组成
res = vars.isalpha()
# 检测字符串是否由纯数字字符组成
res = vars.isdigit()
# 检测当前字符串是否为 空格 字符组成 ' '
res = vars.isspace()

# 检测字符串是否以指定的字符开始的,也可以指定开始和结束的位置
res = vars.startswith('y')
# res = vars.startswith('y',5)
# 检测字符串是否以 指定的字符 结束的,也可以指定开始和结束的位置
# res = vars.endswith('y')
res = vars.endswith('e',1,5)

print(res)

12.6.2. (二)字符串 查找与操作相关函数 重点重点重点

#  ** find() 方法 ,找到则返回字符中符合条件的第一个字符出现的索引位置。未找到返回 -1
res = vars.find('you')
# print(vars[res:res+3])

# index() 方法
# res = vars.index('youe') # 找到则返回索引位置,未找到则报错 ValueError
# print(res)

vars = 'user_admin_id_123'

# ** split() 方法 可以按照指定的分隔符,把字符串分隔成列表
# res = vars.split('_') # ['user', 'admin', 'id', '123']
res = vars.split('_',2)  # ['user', 'admin', 'id_123']
# print(res)

# rsplit() 方法是从右向左进行,从后向前
# res = vars.rsplit('_')  # ['user', 'admin', 'id', '123']
res = vars.rsplit('_',2)  # ['user_admin', 'id', '123']
# print(res)

# ** join() 方法 ,使用指定的字符串,把一个容器中的元素链接成一个字符串
varlist = ['user', 'admin', 'id', '123']
res = '_'.join(varlist)

# ** strip() 去除字符串左右两侧的指定字符
vars = '  zhangsan  '
res = vars.strip(' ')
vars = '@admin'
res = vars.strip('@')
# print(vars)
# print(res)

# rstrip() 去除字符串右侧的指定字符, lstrip() 去除字符串左侧的指定字符

# ** len() 函数可以获取当前字符串的长度
# print(len(vars))
# print(len(res))


# ** replace() 替换函数
vars = 'iloveyou'
# 找到 love  替换为 live
res = vars.replace('love','live')

vars = 'aabbccddeeabcdef'
#  可以限制替换的次数
res = vars.replace('b','B',2)
# print(res)